package cn.org.tpeach.nosql.controller;


import cn.org.tpeach.nosql.enums.RedisTreeType;
import cn.org.tpeach.nosql.framework.LarkFrame;
import cn.org.tpeach.nosql.framework.ServiceProxy;
import cn.org.tpeach.nosql.redis.bean.RedisConnectInfo;
import cn.org.tpeach.nosql.redis.bean.RedisTreeItem;
import cn.org.tpeach.nosql.redis.controller.BaseController;
import cn.org.tpeach.nosql.redis.controller.ResultRes;
import cn.org.tpeach.nosql.redis.service.IRedisConfigService;
import cn.org.tpeach.nosql.redis.service.IRedisConnectService;
import cn.org.tpeach.nosql.service.ICommonService;
import cn.org.tpeach.nosql.tools.DataStructureUtils;
import cn.org.tpeach.nosql.tools.StringUtils;
import cn.org.tpeach.nosql.view.JavaFxUtil;
import cn.org.tpeach.nosql.view.PasswordShowField;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import lombok.Getter;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Getter
public class MainController implements Initializable {

    private final IRedisConfigService redisConfigService = ServiceProxy.getBeanProxy("redisConfigService", IRedisConfigService.class);
    private final  IRedisConnectService redisConnectService = ServiceProxy.getBeanProxy("redisConnectService", IRedisConnectService.class);
    private final ICommonService commonService = ServiceProxy.getBeanProxy("commonService", ICommonService.class);

    @FXML
    private HBox keysFilterBox;
    @FXML
    private Button keysFilterBoxSearch;
    @FXML
    private Button keysFilterBoxAdd;
    @FXML
    private TextField keysFilterBoxTextField;
    @FXML
    private BorderPane leftDbInfoPane;
    @FXML
    private ScrollPane leftTreeScrollPane;
    @FXML
    private HBox noServerDataHbox;
    @FXML
    private SplitPane treeAndDataSplitPane;
    @FXML
    private TreeView<RedisTreeItem> redisTree;
    @FXML
    private TabPane mainInfoTabPane;
    @FXML
    private   TextArea logTextArea;

    @FXML
    private BorderPane logTabBorPane;

    @FXML
    private Label curentServerLabel;

    @FXML
    private Label memUsedLabel;

    @FXML
    private Tab logTab;
    @FXML
    private Tab homeTab;

    @FXML
    private Menu fileMenu;
    @FXML
    private Menu editMenu;
    @FXML
    private MenuItem fileCloseTabMenuItem;
    @FXML
    private MenuItem  fileServerInfoMenuItem;
    @FXML
    private MenuItem editServerMenuItem;
    @FXML
    private MenuItem deleteServerMenuItem;

    private TreeController treeController;

    @FXML
    public void exit(ActionEvent event){
        JavaFxUtil.exit(event);
    }

    @FXML
    public void addServer(ActionEvent event){
        openAddServerDialog(null);
    }

    @FXML
    public void editServer(ActionEvent event){
        TreeItem<RedisTreeItem> serverTreeItem = findServerTreeItem(redisTree.getSelectionModel().getSelectedItem());
        if(serverTreeItem == null ){
            JavaFxUtil.showMessageErrorDialog(null, null,"请选择需要编辑的节点");
            return;
        }
        commonService.editServer(serverTreeItem);
    }
    @FXML
    public void deleteServer(ActionEvent event){
        TreeItem<RedisTreeItem> serverTreeItem = findServerTreeItem(redisTree.getSelectionModel().getSelectedItem());
        if(serverTreeItem == null ){
            JavaFxUtil.showMessageErrorDialog(null, null,"请选择需要删除的节点");
            return;
        }
        commonService.deleteServer(serverTreeItem);
    }

    @FXML
    public void openServerInfo(ActionEvent event){
        TreeItem<RedisTreeItem> treeItem = redisTree.getSelectionModel().getSelectedItem();
        if(treeItem == null){
            return;
        }
        Tab serverTab = null;
        ObservableList<Tab> tabs = mainInfoTabPane.getTabs();
        for (Tab tab : tabs) {
            if("server".equals(tab.getProperties().get("type"))){
                TreeItem<RedisTreeItem> item = (TreeItem<RedisTreeItem>) tab.getProperties().get("selectedItem");
                if(StringUtils.equals(item.getValue().getId(),treeItem.getValue().getId())){
                    serverTab = tab;
                    break;
                }
            }
        }
        if(serverTab == null){
            commonService.openServerInfoTab(findServerTreeItem(treeItem));
            return;
        }
        mainInfoTabPane.getSelectionModel().select(serverTab);

    }

    @FXML
    public void closeMainTab(ActionEvent event){
        Tab tab = mainInfoTabPane.getSelectionModel().getSelectedItem();
        if("home".equals(tab.getProperties().get("type"))){
            return;
        }
        mainInfoTabPane.getTabs().remove(tab);
        JavaFxUtil.closeTabRelease(mainInfoTabPane,tab);
    }


    @FXML
    public void about(ActionEvent event){
        FXMLLoader fxmlLoader = new FXMLLoader();
        try {
            Node node = JavaFxUtil.loadFxml(fxmlLoader, "/view/fxml/about.fxml");
            Dialog<String> dialog = JavaFxUtil.createDialog(node);
            dialog.getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL);
            dialog.show();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        keysFilterBox.widthProperty().addListener((observable, oldValue, newValue) -> prefixKeysFilterTextFieldWidth());
        keysFilterBoxSearch.widthProperty().addListener((observable, oldValue, newValue) -> prefixKeysFilterTextFieldWidth());
        keysFilterBoxAdd.widthProperty().addListener((observable, oldValue, newValue) -> prefixKeysFilterTextFieldWidth());
//        keysFilterBoxTextField.setPrefSize(200, 50); // 设置单行输入框的推荐宽高
//        keysFilterBoxTextField.setEditable(true); // 设置单行输入框能否编辑
//        keysFilterBoxTextField.setPromptText("请输入"); // 设置单行输入框的提示语
//        keysFilterBoxTextField.setAlignment(Pos.CENTER_LEFT); // 设置单行输入框的对齐方式
//        keysFilterBoxTextField.setPrefColumnCount(11); // 设置单行输入框的推荐列数
        //树面板填充完全
        leftTreeScrollPane.setFitToHeight(true);
        leftTreeScrollPane.setFitToWidth(true);
        treeController = TreeController.buildTree(this);

        LarkFrame.executorService.scheduleAtFixedRate(()->{
            Platform.runLater(()->{
                MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
                long used = bean.getHeapMemoryUsage().getUsed();
                memUsedLabel.setText("内存占用:"+StringUtils.getLengthHummanText(used));
            });
        },0,5, TimeUnit.SECONDS);
        updateStatus(null);
        redisTree.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> updateStatus(newValue));
        initHomeTab();
        fileMenu.setOnShowing(event -> {
            Tab selectedItem = mainInfoTabPane.getSelectionModel().getSelectedItem();
            fileCloseTabMenuItem.setDisable("home".equals(selectedItem.getProperties().get("type")));
            fileServerInfoMenuItem.setDisable(!serverIsConnected(redisTree.getSelectionModel().getSelectedItem()));
        });
        editMenu.setOnShowing(event -> {
            TreeItem<RedisTreeItem> selectedItem = redisTree.getSelectionModel().getSelectedItem();
            deleteServerMenuItem.setDisable(selectedItem == null);
            editServerMenuItem.setDisable(selectedItem == null);
        });
        logTextArea.setEditable(false);
        logTextArea.setContextMenu(new ContextMenu());
        ContextMenu contextMenu = logTextArea.getContextMenu();
        MenuItem copyItem = new MenuItem("复制");
        MenuItem selectAllItem = new MenuItem("全选");
        MenuItem clearItem = new MenuItem("清空");
        contextMenu.getItems().addAll(copyItem,selectAllItem,clearItem);
        contextMenu.setOnShowing(event -> copyItem.setDisable(StringUtils.isEmpty(logTextArea.getSelectedText())));
        selectAllItem.setOnAction(event -> logTextArea.selectAll());
        copyItem.setOnAction(event -> logTextArea.copy());
        logTextArea.setUserData(clearItem);
    }

    private void initHomeTab(){
        GridPane borderPane = (GridPane) homeTab.getContent();
        Label redisLabel = new Label("Redis");
        redisLabel.setTextFill(Color.valueOf("4ABC99"));
        redisLabel.setFont(Font.font("Verdana", 35));
        redisLabel.setGraphic(new ImageView("/view/img/redis.png"));
//        borderPane.add(new ImageView("/view/img/home.png"),2,2);
        borderPane.add(redisLabel,0,0,2,1);
        homeTab.getProperties().put("type","home");
    }

    private TreeItem<RedisTreeItem>  findServerTreeItem(TreeItem<RedisTreeItem> item){
        if(item == null){
            return null;
        }
        TreeItem<RedisTreeItem> parent = item;
        while (parent != null) {
            if (parent.getValue() != null && RedisTreeType.SERVER.equals(parent.getValue().getType())) {
                break;
            }
            parent = parent.getParent();
        }
        return parent;
    }

    public void updateStatus( TreeItem<RedisTreeItem> newValue){
        boolean flag = serverIsConnected(newValue);
        if (flag) {
            curentServerLabel.setText("已成功连接到:" + newValue.getValue().getServerName());
            curentServerLabel.setTextFill(Color.rgb(0, 124, 0));
        }else{
            curentServerLabel.setTextFill(Color.rgb(255, 45, 51));
            curentServerLabel.setText("未连接服务");
        }
    }

    public boolean serverIsConnected(TreeItem<RedisTreeItem> newValue) {
        boolean flag = false;
        if(newValue != null && newValue.getValue() != null) {
            TreeItem<RedisTreeItem> parent = findServerTreeItem(newValue);
            if (parent != null && DataStructureUtils.isNotEmpty(parent.getChildren())) {
                ObservableList<TreeItem<RedisTreeItem>> children = parent.getChildren();
                flag  = true;
                for (TreeItem<RedisTreeItem> child : children) {
                    if(RedisTreeType.LOADING.equals(child.getValue().getType())){
                        flag = false;
                        break;
                    }
                }
            }
        }
        return flag;
    }

    public void hasServerData(){
        ObservableList<TreeItem<RedisTreeItem>> children = redisTree.getRoot().getChildren();
        boolean empty = DataStructureUtils.isEmpty(children);
        this.getNoServerDataHbox().setVisible(empty);
        this.getNoServerDataHbox().setManaged(empty);
        this.getLeftTreeScrollPane().setVisible(!empty);
        this.getLeftTreeScrollPane().setManaged(!empty);
    }

    public  void openAddServerDialog(RedisConnectInfo oldConnectInfo) {

        try {
            FXMLLoader fxmlLoader = new FXMLLoader();
//            Node node = FXMLLoader.load(getClass().getResource("/view/fxml/addServer.fxml"));
            AtomicBoolean canClose = new AtomicBoolean(false);
            Node node = JavaFxUtil.loadFxml(fxmlLoader, "/view/fxml/addServer.fxml");
            Dialog<String> dialog = JavaFxUtil.createDialog(node);
            ButtonType configButtonType = new ButtonType("确定", ButtonBar.ButtonData.OK_DONE);
            ButtonType testButtonType = new ButtonType("测试", ButtonBar.ButtonData.LEFT);
            dialog.getDialogPane().getButtonTypes().addAll(testButtonType, configButtonType, ButtonType.CANCEL);
            dialog.setResult(StringUtils.EMPTY);
            AddServerController controller = fxmlLoader.getController();
            Button configButton = (Button) dialog.getDialogPane().lookupButton(configButtonType);
            Button testButton = (Button) dialog.getDialogPane().lookupButton(testButtonType);
            Button cancelButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.CANCEL);
            cancelButton.setOnAction(event -> {
                canClose.set(true);
                dialog.close();
            });
            controller.initialize(dialog, oldConnectInfo, configButton, testButton, redisTree, canClose);
            dialog.setOnCloseRequest(event -> {
                if (!canClose.get()) {
                    event.consume();
                }
            });
            dialog.show();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void keysFilterSearchAction(Event event){
        if (event instanceof KeyEvent && ((KeyEvent )event).getCode() != KeyCode.ENTER)  {
            return;
        }
        //搜索
        TreeItem<RedisTreeItem> selectedItem = redisTree.getSelectionModel().getSelectedItem();
        if(selectedItem == null || selectedItem.getValue() == null || !RedisTreeType.DATABASE.equals(selectedItem.getValue().getType())){
            JavaFxUtil.showMessageErrorDialog(LarkFrame.primaryStage,null,"请选择检索的数据库");
            return;
        }
        treeController.openDbRedisTree(selectedItem,selectedItem.getValue(),true);

    }


    /**
     * 搜索文本框宽度变化
     */
    private void prefixKeysFilterTextFieldWidth(){
        if(0 !=keysFilterBoxSearch.getWidth() && 0 !=keysFilterBoxAdd.getWidth() ){
            Insets padding = keysFilterBox.getPadding();
            double width =  keysFilterBox.getWidth() - keysFilterBoxSearch.getWidth() - keysFilterBoxAdd.getWidth()-keysFilterBox.getSpacing() * 2-padding.getLeft()-padding.getRight();
            keysFilterBoxTextField.setMinWidth(width);
        }
    }
}
